package com.je.gateway.filter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Strings;
import com.je.common.auth.HtmlView;
import com.je.gateway.filter.loader.FilterParamsXmlLoader;
import com.je.gateway.xml.ConfigResourceLoader;
import org.apache.servicecomb.common.rest.RestConst;
import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
import org.apache.servicecomb.core.Invocation;
import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import org.apache.servicecomb.swagger.invocation.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.Part;
import java.util.*;

import static com.je.gateway.router.dispatcher.GatewayAbstractRestDispatcher.X_COOKIE_KEY;

@Component
public class GatewayHttpClientFilter implements HttpClientFilter {

    private static final Logger logger = LoggerFactory.getLogger(GatewayHttpClientFilter.class);

    private static final List<String> notIncloudHeaderKeys = Lists.newArrayList("Accept",
            "Accept-Encoding", "Connection", "Content-Length", "Host");
    /**
     * status key
     */
    private static final String REDIRECT_STATUS_KEY = "status";
    /**
     * location key
     */
    private static final String REDIRECT_LOCATION_KEY = "location";
    /**
     * location key
     */
    private static final String REDIRECT_HEADERS_KEY = "headers";
    /**
     * location key
     */
    private static final String REDIRECT_COOKIES_KEY = "cookies";

    private static final String HTML_VIEW_SPEC_KEY = "toSpec";

    private static final String HTML_VIEW_CONTENT_KEY = "rcontent";

    private ConfigResourceLoader<Map<String, Object>> loader = new FilterParamsXmlLoader();

    public static Map<String, Object> params;

    public GatewayHttpClientFilter() {
        params = loader.load();
    }

    @Override
    public int getOrder() {
        return 50;
    }

    @Override
    public void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx) {
        RestClientRequestImpl restClientRequest = (RestClientRequestImpl) invocation.getHandlerContext()
                .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT);
        HttpServletRequestEx hsre = invocation.getRequestEx();

        //用户真实ip
        restClientRequest.putHeader("X-Real-IP", hsre.getHeader("X-Real-IP"));
        restClientRequest.putHeader(GatewayFilterConstants.X_AUTH_TOKEN, hsre.getHeader(GatewayFilterConstants.X_AUTH_TOKEN));

        //params
        List<String> noConversionList = params.get(FilterParamsXmlLoader.NO_CONVERTION_KEY) == null ? null : (List<String>) params.get(FilterParamsXmlLoader.NO_CONVERTION_KEY);
        Map<String, String[]> params = hsre.getParameterMap();
        for (Map.Entry<String, String[]> eachEntry : params.entrySet()) {
            if (!noConversionList.contains(eachEntry.getKey())) {
                restClientRequest.addForm(eachEntry.getKey(), eachEntry.getValue() == null ? null : eachEntry.getValue()[0]);
                continue;
            }
            logger.info("No conversion param {} value {}", eachEntry.getKey(), eachEntry.getValue()[0]);
        }

        try {
            Collection<Part> parts = hsre.getParts();
            if (parts != null && parts.size() > 0) {
                for (Iterator<Part> iterator = parts.iterator(); iterator.hasNext(); ) {
                    Part part = iterator.next();
                    restClientRequest.attach(part.getName(), part);
                }
                requestEx.setBodyBuffer(restClientRequest.getBodyBuffer());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

//        Enumeration<String> headerEnum = hsre.getHeaderNames();
//        String eachKey;
//        while (headerEnum.hasMoreElements()) {
//            eachKey = headerEnum.nextElement();
//            if (notIncloudHeaderKeys.contains(eachKey)) {
//                continue;
//            }
//            restClientRequest.putHeader(eachKey, hsre.getHeader(eachKey));
//        }
    }

    @Override
    public Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx) {
        if (responseEx.getBodyBytes() == null || responseEx.getBodyBytes().length <= 0) {
            return null;
        }
        if (!JSON.isValid(responseEx.getBodyBytes())) {
            return null;
        }

        Object resBody = JSON.parse(responseEx.getBodyBytes());
        if (!(resBody instanceof JSONObject)) {
            return null;
        }

        //判断是否是redirect view
        JSONObject jsonResObj = (JSONObject) resBody;
        if (jsonResObj.containsKey(REDIRECT_STATUS_KEY)
                && jsonResObj.containsKey(REDIRECT_LOCATION_KEY)
                && jsonResObj.containsKey(REDIRECT_HEADERS_KEY)) {
            Response response = Response.create(jsonResObj.getInteger(REDIRECT_STATUS_KEY), "", null);
            JSONObject headerObj = jsonResObj.getJSONObject(REDIRECT_HEADERS_KEY);
            if (!Strings.isNullOrEmpty(jsonResObj.getString(REDIRECT_LOCATION_KEY))) {
                response.addHeader("location", jsonResObj.getString(REDIRECT_LOCATION_KEY));
            }
            if (headerObj != null) {
                for (String eachKey : headerObj.keySet()) {
                    response.addHeader(eachKey, headerObj.getString(eachKey));
                    response.addHeader("Content-Type", "text/html");
                }
            }

            if (jsonResObj.containsKey(REDIRECT_COOKIES_KEY)) {
                JSONObject cookieObj = jsonResObj.getJSONObject(REDIRECT_COOKIES_KEY);
                if (cookieObj != null) {
                    StringBuilder cookieKeyBuffer = new StringBuilder();
                    for (String key : cookieObj.keySet()) {
                        if (Strings.isNullOrEmpty(cookieKeyBuffer.toString())) {
                            cookieKeyBuffer.append(key);
                        } else {
                            cookieKeyBuffer.append(",");
                            cookieKeyBuffer.append(key);
                        }
                        response.addHeader(X_COOKIE_KEY, cookieKeyBuffer.toString());
                        response.addHeader(key, cookieObj.getString(key));
                    }
                }
            }
            return response;
        } else if (jsonResObj.containsKey(HTML_VIEW_SPEC_KEY)
                && HtmlView.HTML_VIEW.equals(jsonResObj.get(HTML_VIEW_SPEC_KEY))) {
            invocation.getContext().put(HtmlView.HTML_VIEW, "text/html");
            Response response = Response.createSuccess(jsonResObj.getString(HTML_VIEW_CONTENT_KEY));
            response.addHeader(HtmlView.HTML_VIEW, "text/html");
            return response;
        }

        return null;
    }
}
